﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace Aim2.Screen {
    public class ScreenManager : DrawableGameComponent {
        List<GameScreen> screens = new List<GameScreen>();
        IGraphicsDeviceService graphicsDeviceService;
        SpriteBatch spriteBatch;
        public static Texture2D blankTexture; //TODO: enlever le public static
        SpriteFont scoreFont;
        SpriteFont menuFont;
        SpriteFont counterFont;
        InputState input = new InputState();
        public ContentManager Content { get; set; }

        /// <summary>
        /// Constructs a new screen manager component.
        /// </summary>
        public ScreenManager(Game game)
            : base(game) {
            Content = new ContentManager(game.Services, "Content");

            graphicsDeviceService = (IGraphicsDeviceService)game.Services.GetService(
                                                        typeof(IGraphicsDeviceService));

            if (graphicsDeviceService == null)
                throw new InvalidOperationException("No graphics device service.");
        }

        /// <summary>
        /// Load your graphics content.
        /// </summary>
        protected override void LoadContent() {
            // Load content belonging to the screen manager.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            scoreFont = Content.Load<SpriteFont>("Fonts/ScoreFont");
            menuFont = Content.Load<SpriteFont>("Fonts/MenuFont");
            counterFont = Content.Load<SpriteFont>("Fonts/CounterFont");
            blankTexture = Content.Load<Texture2D>("Textures/blank");

            // Tell each of the screens to load their content.
            foreach (GameScreen screen in screens) {
                screen.LoadContent();
            }
        }

        public override void Draw(GameTime gameTime) {
            foreach (GameScreen screen in screens) {
                screen.Draw(gameTime);
            }
        }

        public override void Update(GameTime gameTime) {
            // Read the keyboard and gamepad.
            input.Update();

            // Make a copy of the master screen list, to avoid confusion if
            // the process of updating one screen adds or removes others
            // (or it happens on another thread)


            bool otherScreenHasFocus = !Game.IsActive;
            bool coveredByOtherScreen = false;


            for(int i = screens.Count - 1; i >= 0; i--) {
                GameScreen screen = screens[i];
                // Update the screen.
                screen.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);

                if (screen.ScreenState == ScreenState.TransitionOn ||
                    screen.ScreenState == ScreenState.Active) {
                    // If this is the first active screen we came across,
                    // give it a chance to handle input and update presence.
                    if (!otherScreenHasFocus) {
                        screen.HandleInput(input);


                        otherScreenHasFocus = true;
                    }

                    // If this is an active non-popup, inform any subsequent
                    // screens that they are covered by it.
                    if (!screen.IsPopup)
                        coveredByOtherScreen = true;
                }
            }

        }


        #region Public Methods


        /// <summary>
        /// Adds a new screen to the screen manager.
        /// </summary>
        public void AddScreen(GameScreen screen) {
            screen.ScreenManager = this;

            // If we have a graphics device, tell the screen to load content.
            if ((graphicsDeviceService != null) &&
                (graphicsDeviceService.GraphicsDevice != null)) {
                screen.LoadContent();

                BackgroundScreen.Background.TimeToNextSecondaryColor = BackgroundScreen.Background.TimeBetweenBeats * 4;
                BackgroundScreen.Background.ToSecondaryColor = Color.DarkBlue;
            }

            screens.Add(screen);
        }


        /// <summary>
        /// Removes a screen from the screen manager. You should normally
        /// use GameScreen.ExitScreen instead of calling this directly, so
        /// the screen can gradually transition off rather than just being
        /// instantly removed.
        /// </summary>
        public void RemoveScreen(GameScreen screen) {
            // If we have a graphics device, tell the screen to unload content.
            if ((graphicsDeviceService != null) &&
                (graphicsDeviceService.GraphicsDevice != null)) {
                screen.UnloadContent();
            }

            screens.Remove(screen);
        }


        /// <summary>
        /// Expose an array holding all the screens. We return a copy rather
        /// than the real master list, because screens should only ever be added
        /// or removed using the AddScreen and RemoveScreen methods.
        /// </summary>
        public GameScreen[] GetScreens() {
            return screens.ToArray();
        }


        /// <summary>
        /// Helper draws a translucent black fullscreen sprite, used for fading
        /// screens in and out, and for darkening the background behind popups.
        /// </summary>
        public void FadeBackBufferToBlack(int alpha) {
            Viewport viewport = GraphicsDevice.Viewport;

            spriteBatch.Begin();

            spriteBatch.Draw(blankTexture,
                             new Rectangle(0, 0, viewport.Width, viewport.Height),
                             new Color(0, 0, 0, (byte)alpha));

            spriteBatch.End();
        }

        /// <summary>
        /// A default SpriteBatch shared by all the screens. This saves
        /// each screen having to bother creating their own local instance.
        /// </summary>
        public SpriteBatch SpriteBatch {
            get { return spriteBatch; }
        }


        public SpriteFont ScoreFont {
            get { return scoreFont; }
        }

        public SpriteFont MenuFont {
            get { return menuFont; }
        }

        public SpriteFont CounterFont {
            get { return counterFont; }
        }

        public void DrawRectangle(Rectangle rectangle, Color color) {
            SpriteBatch.Begin();
            SpriteBatch.Draw(blankTexture, rectangle, color);
            SpriteBatch.End();
        }

        public static void ChangeBackgroundColors(bool primary, Color newColor, float timeToChange) {
            if (primary) {
                BackgroundScreen.Background.TimeToNextPrimaryColor = timeToChange;
                BackgroundScreen.Background.ToPrimaryColor = newColor;
            }
            else {
                BackgroundScreen.Background.TimeToNextSecondaryColor = timeToChange;
                BackgroundScreen.Background.ToSecondaryColor = newColor;
            }
        }

        public static void ChangeTilesRotation(bool r) {
            BackgroundScreen.Background.Tiles.DoRotation = r;
        }

        public static void InitTransitionTilesSpeed(float t, float v) {
            BackgroundScreen.Background.InitTransitionTilesSpeed(t, v);
        }

        public static void InitTransitionTilesSizeX(float t, float v) {
            BackgroundScreen.Background.InitTransitionTilesSizeX(t, v);
        }

        public static void InitTransitionTilesSizeY(float t, float v) {
            BackgroundScreen.Background.InitTransitionTilesSizeY(t, v);
        }

        public static void InitTransitionBarsSize(float t, float v) {
            BackgroundScreen.Background.InitTransitionBarsSize(t, v);
        }

        public static void ChangeBarsNumber(int i) {
            BackgroundScreen.Background.Bars.NumberOfBarsLayers = i;
        }

        public static void ChangeBarFormula(BarFormula b) {
            BackgroundScreen.Background.Bars.BarFormula = b;
        }

        public static void ChangeBarSizeFormula(bool b) {
            BackgroundScreen.Background.Bars.BarSizeFormula = b;
        }

        #endregion
    }
}
